Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[3.0] Changes WebApp to use Express under the hood #12442

Merged
merged 25 commits into from
Jan 19, 2023

Conversation

Grubba27
Copy link
Contributor

@Grubba27 Grubba27 commented Jan 13, 2023

Sorry about the number of files and changes

This PR focuses on changing connect framework for the Express framework.

Why is this happening?

The way connect handles async handlers is kind of awkward because it was made at a different time than ours, while we were removing fibers we decided to do another upgrade in the MeteorJS core. Give a more modern-ish look for core functionality.

To make async code work properly you would need to do something like this in your codebase:

 app.use(async function middleware1(req, res, next) {
    // middleware 1
   // if error occurs will rang
    const getFoo = await FooCol.find({}).fetchAsync();
    next();
  });

 //this is fine
 app.use(async function middleware2(req, res, next) {
    try{
      const getFoo = await FooCol.find({}).fetchAsync();
      next();
    } catch (e){next(e)}
  });

We could have a function like @radekmie has shown me:

function wrap(fn) {
  return (request, response, next) => {
    Promise.resolve().then(fn).then(() => next(), next);
  };
}

and could be used like this to have the same functionality that we have in Express:

WebApp.connectHandlers.use(wrap(async (request, response) => {
  // ...
}));

Now with the new API the code above can be replaced with the following:

WebApp.expressHandlers.use(async (request, response) => {
  // ...
});

Does not seems much, but this will help us a lot in the core, and the community in the long term, as we can benefit a lot more from having 100% compatibility with the express plugin ecosystem.

But express was built on top of connect why the change?

From express docs:

Express 4 no longer depends on Connect, and removes all built-in middleware from its core, except for the express.static function. This means that Express is now an independent routing and middleware web framework

This is an overall improvement as we can do it all the same way as before but now our webapp package is a little bit more complete.

What changes for me?

this was extracted from the history.md

  • WebApp.connectHandlers.use(middleware) is now WebApp.expressHandlers.use(middleware)
  • WebApp.rawConnectHandlers.use(middleware) is now WebApp.rawExpressHandlers.use(middleware)
  • WebApp.connectApp is now WebApp.expressApp

If you have an edge case that may break because of compatibility issues here is express 4 migration guide


Running against devel tests:

Screenshot 2023-01-16 at 10 25 07


This closes #12447

Copy link
Collaborator

@filipenevola filipenevola left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems very interesting.

I would like to see this PR against current devel/master just to make sure everything is still working as expected.

Later we could apply it on top of 3.0 as I think this would be the right place to merge it.

What do you think @Grubba27 ?

@Grubba27
Copy link
Contributor Author

Sounds great!
I will try do this as soon as possible!
I did tried running all tests, all but 1 ran smoothly, I did not waited it finish but I think it will be okay.

Copy link
Collaborator

@radekmie radekmie left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My only concern about this change are the defaults of connect and express. For example, I think we definitely should opt out of X-Powered-By:

app.disable('x-powered-by');

And there are other things like that, including ETags. It may affect the performance and probably security significantly.

packages/webapp/webapp.d.ts Outdated Show resolved Hide resolved
Co-authored-by: Radosław Miernik <radekmie@gmail.com>
@github-actions github-actions bot temporarily deployed to pull request January 16, 2023 12:33 Inactive
@Grubba27
Copy link
Contributor Author

And there are other things like that, including ETags. It may affect the performance and probably security significantly.

Can you enumerate a little bit more? I will make the adjustments with app.disable('x-powered-by'); and app.set('etag', false);
cc: @radekmie

@github-actions github-actions bot temporarily deployed to pull request January 16, 2023 13:03 Inactive
@Grubba27 Grubba27 mentioned this pull request Jan 16, 2023
@Grubba27
Copy link
Contributor Author

Grubba27 commented Jan 16, 2023

Screenshot 2023-01-16 at 10 25 07
Running against devel/ without fibers
cc: @filipenevola

@zodern
Copy link
Member

zodern commented Jan 16, 2023

Replacing connect with something that has a router will be very nice.

It seems one of the main reasons for doing this now is express handles promise rejections better. This is coming in express 5, which is still in beta. As far as I know, express 4 doesn't handle it any better than connect does. We already modify connect so it supports fibers. We could do the same thing with connect or express so it handles rejected promises.

Since there are so many breaking changes in Meteor 3, I'm wondering if there is a way to switch to express in a way that doesn't add more. It is possible to use express as a middleware for connect. Instead of removing connect completely, we could keep it for now, and add WebApp.expressHandlers which runs after WebApp.rawConnectHandlers and maybe before WebApp.connectHandlers. Existing code could work as is until projects are ready to migrate, and new code can use express. Later connect could be deprecated and removed.

@Grubba27
Copy link
Contributor Author

IMHO this:

We could do the same thing with connect or express, so it handles rejected promises.

It would be the best, but at the same time, I think that if we have the chance to move into something that is more well-known, it would be good for MeteorJS adoption.

Regarding the amount of changes that we will have on this 3.0, it seems overwhelming. At the same time, it would be hard to maintain both connect and express. Let's take this chance of having a breaking change and move a few pieces because if we cannot change now, when can we?

@radekmie
Copy link
Collaborator

And there are other things like that, including ETags. It may affect the performance and probably security significantly.

Can you enumerate a little bit more? I will make the adjustments with app.disable('x-powered-by'); and app.set('etag', false);

@Grubba27 First of all, I think it has to be done for every express instance, not only the top-level one. Secondly, I'm not sure there's anything else, but the best and easiest would be to run the app with and without this change, save curl -v localhost:3000 result to a file and compare the headers and the rest of the output for a few endpoints (/, some dynamic import, a static file).

@Grubba27
Copy link
Contributor Author

Grubba27 commented Jan 16, 2023

With express without disabling etag and x-powered-by:
Screenshot 2023-01-16 at 19 13 02

With connect:
Screenshot 2023-01-16 at 19 07 27

With express disabling etag and x-powered-by

Screenshot 2023-01-16 at 19 16 17

cc: @radekmie

@github-actions github-actions bot temporarily deployed to pull request January 16, 2023 22:45 Inactive
@rj-david
Copy link
Contributor

What changes for me?

this was extracted from the history.md

  • WebApp.connectHandlers.use(middleware) is now WebApp.expressHandlers.use(middleware)
  • WebApp.rawConnectHandlers.use(middleware) is now WebApp.rawExpressHandlers.use(middleware)
  • WebApp.connectApp is now WebApp.expressApp

@Grubba27, am I correct with the following migration paths:

  1. Custom handlers, just update the object to WebApp.express*
  2. Npm middlewares, same as number 1
  3. Meteor packages (e.g. restivus) - fork the package and do number 1

Did I miss anything?

packages/webapp/webapp.d.ts Outdated Show resolved Hide resolved
packages/webapp/webapp_server.js Outdated Show resolved Hide resolved
@Grubba27
Copy link
Contributor Author

Hey, @rj-david, I would say that it Is a good practice just take a look at express 4 migration just in case you use a very specific connect feature that was not ported to express, I will update the docs & PR description to reflect this

@github-actions github-actions bot temporarily deployed to pull request January 18, 2023 20:46 Inactive
Copy link
Member

@henriquealbert henriquealbert left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great work as always @Grubba27 🎉

@StorytellerCZ
Copy link
Collaborator

Well #12410 happened much earlier than I expected. 😂

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

9 participants